package application

import (
	"context"
	"errors"
	"time"

	"github.com/redis/go-redis/v9"
	"github.com/samber/do/v2"
	"github.com/spf13/viper"

	"gitee.com/monkeyPP/happy-mall/pkg/log"
	"gitee.com/monkeyPP/happy-mall/services/userservice/internal/pkg/auth"
	"gitee.com/monkeyPP/happy-mall/services/userservice/internal/pkg/cache"
)

type AuthApp interface {
	Refresh(ctx context.Context, token string) (*auth.TokenPair, error)
}

type AuthAppImpl struct {
	redisClient *redis.Client
}

func NewAuthApp(i do.Injector) (AuthApp, error) {
	redisClient := do.MustInvoke[*redis.Client](i)
	return &AuthAppImpl{
		redisClient: redisClient,
	}, nil
}

func (a *AuthAppImpl) Refresh(ctx context.Context, refreshToken string) (*auth.TokenPair, error) {
	claim, err := auth.ValidateRefreshToken(refreshToken)
	if err != nil {
		return nil, err
	}

	// 如果 key 在 redis 里不存在
	key := cache.GenerateRefreshTokenKey(claim.UserID)
	cmd := a.redisClient.Get(ctx, key)
	if cmd.Err() != nil {
		return nil, cmd.Err()
	}

	log.C(ctx).Infow("refresh token in redis", "key", key, "value", cmd.Val())
	if cmd.Val() != refreshToken {
		return nil, errors.New("refresh token is invalid")
	}

	tokenPair, err := auth.GenerateTokenPair(claim.UserID)
	if err != nil {
		return nil, err
	}

	// 将 refreshToken 存到 redis
	expiryTime := viper.GetInt("jwt.refresh_expiry")
	setCmd := a.redisClient.Set(ctx, key, tokenPair.RefreshToken, time.Duration(expiryTime)*time.Second)
	if setCmd.Err() != nil {
		return nil, setCmd.Err()
	}

	return tokenPair, nil
}
